package org.jeecg.codegeneweb;

import cn.hutool.core.util.StrUtil;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.codegeneweb.mapsetfromwo.OneMapSet;
import org.jeecg.codegeneweb.mock.OneMockWebModelVo;
import org.jeecg.codegeneweb.template.TemplateLocaltion;
import org.jeecg.codegeneweb.template.TemplateSingleFileDomain;
import org.jeecg.codegeneweb.template.ext.ExtDestinationLocation;
import org.jeecg.codegeneweb.template.ext.ExtTemplateLocaltion;
import org.jeecg.codegeneweb.template.ext.ExtTemplateSingleFileDomain;
import org.jeecg.codegeneweb.util.FileSplitter;
import org.jeecg.codegeneweb.util.Templcateconfig;
import org.jeecg.codegeneweb.vo.WebModelVo;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
@Data
public class FreemakerEngineImpl implements FreemakerEngine {

    @Override
    public void processextenh(Map<String, Object> map, ExtTemplateLocaltion templateLocaltion, ExtDestinationLocation destinationLocation) throws Exception {
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
        //获取到模板目录下的所有文件
        List<File> files = getFileList(new File(templateLocaltion.getTemplatePath()));
        for (File file : files) {
            //设置双方关系
            ExtTemplateSingleFileDomain ef=new ExtTemplateSingleFileDomain();
            ef.setExttemplateLocaltion(templateLocaltion);
            templateLocaltion.getExttemplateSingleFileDomains().add(ef);

            String templatepath=templateLocaltion.getTemplatePath();
            String templatefixpart=ef.getFixpart();

            String templatefullpath=file.getAbsolutePath();
            //将模板的绝对路径按照 ${bussiPackage}+ ${entityPackage} 和"\\${bussiPackage}" 进行拆分

            //原始模板的路径分为 templatepath +  ${bussiPackage}+ ${entityPackage} + 控制层的mapper.service.java路径
            //模板的路径为 目标地址+srcmainjava+${bussiPackage}+ ${entityPackage} + 控制层的mapper.service.java路径
            //所以，需要将原始模板的最后一个部分拿出来，放入到模板的目标地址中
            String fixparttwo="\\${bussiPackage}"+"\\${entityPackage}";
            String fixpartone="\\${bussiPackage}";
            //拆分之后，获取到 控制层的mapper.service.java路径，这个路径会被 加入到目标对象中。
            String controlentitymapperservicepath="";
            if(StrUtil.contains(templatefullpath,fixparttwo)){
                //如果是文件，那么它的路径为
                controlentitymapperservicepath=StrUtil.subAfter(templatefullpath,templatefixpart,true);
            }else{
                //如果是目录，那么它的路径为
                controlentitymapperservicepath=StrUtil.subAfter(templatefullpath,fixpartone,true);
            }



            String destprojectpath=destinationLocation.getProject_path();
            String srcmainjava=destinationLocation.getSrcmainjava();
            String entitypackage=destinationLocation.getEntitypackage();

            String defullpath="";
            if(controlentitymapperservicepath.length()>0){
                defullpath=destprojectpath+File.separator+srcmainjava
                        +File.separator+PublicPara.getBussiPackagePath()+File.separator+destinationLocation.getEntitypackage()+File.separator+controlentitymapperservicepath;
            }else {
                defullpath=destprojectpath+File.separator+srcmainjava
                        +File.separator+PublicPara.getBussiPackagePath()+destinationLocation.getEntitypackage();
            }
            System.out.println(defullpath);

            //先得到完整的目标的路径，这个路径上有变量，然后进行路径的替换

            //第一次替换：替换掉上面的变量
            StringWriter stringWriter = new StringWriter();
            Template template = new Template("templateString...", new StringReader(defullpath), configuration);
            template.process(map, stringWriter);
            System.out.println(stringWriter);

            //第二次替换：去掉vuei，javai
            String secondreplace=stringWriter.toString();
            if (secondreplace.endsWith("javai") || secondreplace.endsWith("vuei")|| secondreplace.endsWith("tsi")) {

                secondreplace=secondreplace.substring(0, secondreplace.length() - 1);
            }
            //第三次替换:__变换为.
            secondreplace=secondreplace.replace("__",".");

            //替换结束之后，选择所有的非目录的文件，进行创建文件，并创建它的父目录。
            //因为在ftl中，有引用其他的文件，进行多文件的替换，后面要修改为相对路径。

            //File destfile=new File(stringWriter.toString());
            File destfile=new File(secondreplace);
            destinationLocation.getDestinationFileList().add(destfile);
            boolean isDir=StrUtil.subAfter(destfile.getName(),".",true).equals("");
            if(!isDir){
                if(!destfile.getParentFile().exists()) {
                    destfile.getParentFile().mkdirs();
                }
                    //然后对这个文件开始进行替换操作
//                    destfile.createNewFile();
                    // 设置模板目录
                    //configuration.setDirectoryForTemplateLoading(file.getParentFile());
                FileTemplateLoader[] fileTemplateLoaders = new FileTemplateLoader[2];
                FileTemplateLoader loader1=new FileTemplateLoader(file.getParentFile());
                FileTemplateLoader loader2=new FileTemplateLoader(new File("D:\\book20241011\\jeecg\\JeecgBoot-3.7.1\\jeecg-boot\\jeecg-module-system\\jeecg-system-biz\\src\\main\\resources\\jeecg\\code-template-online"));
                fileTemplateLoaders[0]=loader1;
                fileTemplateLoaders[1]=loader2;
                // 创建 MultiTemplateLoader
                MultiTemplateLoader multiLoader = new MultiTemplateLoader(fileTemplateLoaders);
                configuration.setTemplateLoader(multiLoader);
                configuration.setNumberFormat("###############");
                configuration.setBooleanFormat("true,false");
                configuration.setDefaultEncoding("UTF-8");
                // 获取模板
                Template templatereplacecode=configuration.getTemplate(file.getName());//"template.ftl"
                templatereplacecode.setOutputEncoding("UTF-8");
                BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destfile), "UTF-8"));
                templatereplacecode.process(map, bufferedWriter);
                bufferedWriter.close();


//                if(destfile.getName().startsWith("[1-n]")){
//                    try {
//                        new FileSplitter().splitFileAndDeleteOriginal(destfile);
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
//                }

                }
            }

            //单独处理特殊的oneToMany的文件分拆为多个(destinationLocation);//这个时候，已经生成了代码。在生成后进行分拆，并且原始的要进行删除
           单独处理特殊的oneToMany的文件分拆为多个(destinationLocation);

        }

    private void 单独处理特殊的oneToMany的文件分拆为多个(ExtDestinationLocation dsl) {
        List<File> fileList=dsl.getDestinationFileList();
        for(File file:fileList){
            System.out.println(file.getAbsolutePath());
            if(!file.isDirectory()&&file.getName().startsWith("[1-n]")){
                if(file.getName().startsWith("[1-n]Form.vue")){
                    System.out.println("debug stop");
                }
                try {
                    new FileSplitter().splitFileAndDeleteOriginal(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private List<File> getDirectoryList(List<File> files) {
        List<File> filelist = new ArrayList<>();
        for (File file : files) {
            if (file.isDirectory()) {
                filelist.add(file);
            }
        }
        return filelist;
    }



    public List<String> replace模板中的文件名及变量(List<File> files, Map<String, Object> map,DestinationLocation destinationLocation) {
        List<String> filenamelist = new ArrayList<>();
        for (File file : files) {
            //如果后缀是javai，那么去掉i
            String filename=file.getAbsolutePath();
            if (file.getName().endsWith("javai") || file.getName().endsWith("vuei")) {

                filename=filename.substring(0, filename.length() - 1);
             }
            filenamelist.add(filename);
        }
        List<String> afterfilenamelist = replace模版中的变量(filenamelist, map);
        //将模板中的文件名截取后部分与 目标地址的前部分进行合并
        List<String>filenamefinal=destinationLocation.combinefilenameext(afterfilenamelist);
        return afterfilenamelist;
    }

    public List<String> replace模版中的变量(List<String> filenamelist, Map<String, Object> map) {
        List<String> afterfilenamelist = new ArrayList<>();
        //对文件名的变量进行替换
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
        for (String filename : filenamelist) {
            StringWriter stringWriter = new StringWriter();

            try {
                Template template = new Template("templateString...", new StringReader(filename), configuration);
                template.process(map, stringWriter);
                //return stringWriter.toString();
                afterfilenamelist.add(stringWriter.toString());

            } catch (Exception ex) {
                throw new IllegalStateException("cannot process templateString:" + filename + " cause:" + ex, ex);
            }
        }
        return afterfilenamelist;
    }

    /**
     * 递归获取路径下所有文件夹和文件
     *
     * @param folder 文件路径
     */
    public List<File> getFileList(File folder) {
        List<File> list = new ArrayList<File>();
        File[] files = folder.listFiles();
        for (File file : files) {
            list.add(file);
            if (file.isDirectory()) {
                List<File> fileList = getFileList(file);
                list.addAll(fileList);
            }
        }
        return list;
    }

    public static void process(Template template, Map<String, Object> mapData, File destinationFile, String baseCodeUTF8) throws IOException, TemplateException {
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destinationFile), baseCodeUTF8));
        template.process(mapData, bufferedWriter);
        bufferedWriter.close();
    }

    public static void main(String[] args) throws Exception, TemplateException {
        WebModelVo webModelVo= OneMockWebModelVo.initWo();
        Map map=new HashMap();
        OneMapSet oneMapSet=new OneMapSet();
        oneMapSet.buildMap(map,webModelVo);
        //补充以下map
        map.put("currentDate", "2024-10-11");

        Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
        String templatfile="D:\\book20241011\\jeecg\\JeecgBoot-3.7.1\\jeecg-boot\\jeecg-module-system\\jeecg-system-biz\\src\\main\\resources\\jeecg\\code-template-online\\default\\one\\java\\${bussiPackage}\\${entityPackage}\\entity\\${entityName}.javai";
        File file=new File(templatfile);
        FileTemplateLoader[] fileTemplateLoaders = new FileTemplateLoader[2];
        FileTemplateLoader loader1=new FileTemplateLoader(file.getParentFile());
        FileTemplateLoader loader2=new FileTemplateLoader(new File("D:\\book20241011\\jeecg\\JeecgBoot-3.7.1\\jeecg-boot\\jeecg-module-system\\jeecg-system-biz\\src\\main\\resources\\jeecg\\code-template-online"));
        fileTemplateLoaders[0]=loader2;
        fileTemplateLoaders[1]=loader1;
        // 创建 MultiTemplateLoader
        MultiTemplateLoader multiLoader = new MultiTemplateLoader(fileTemplateLoaders);
        configuration.setTemplateLoader(multiLoader);
        // 获取模板
        Template templatereplacecode=configuration.getTemplate(file.getName());//"template.ftl"
        templatereplacecode.setOutputEncoding("UTF-8");
        File destfiledir=new File("d:\\jeecg4");
        destfiledir.mkdir();
        File destfile=new File("d:\\jeecg4\\1.java");
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destfile), "UTF-8"));
        templatereplacecode.process(map, bufferedWriter);
        bufferedWriter.close();

    }
}
